package com.stars.easyms.datasource.interceptor;

import com.stars.easyms.datasource.*;
import com.stars.easyms.datasource.annotation.SpecifyDataSource;
import com.stars.easyms.datasource.exception.DataSourceInterceptorException;
import com.stars.easyms.datasource.holder.EasyMsMasterSlaveDataSourceHolder;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.annotation.ElementType;
import java.lang.reflect.Method;

/**
 * <p>className: SpecifyDataSourceInterceptor</p>
 * <p>description: SpecifyDataSource注解方法拦截器：Controller、Service、Dao越上层优先级越高</p>
 *
 * @author guoguifang
 * @version 1.2.1
 * @date 2019-03-15 16:33
 */
public final class SpecifyDataSourceInterceptor extends BaseEasyMsDatasourceMethodInterceptor {

    private EasyMsMultiDataSource easyMsMultiDataSource;

    private ElementType elementType;

    @Override
    public Object interceptMybatisMethod(MethodInvocation methodInvocation, Class<?> mapperInterface, Method method)
            throws DataSourceInterceptorException {

        // 判断是否已经确定使用哪个数据源，若已确定则不再重复确定（越上层优先级越高）
        if (EasyMsMasterSlaveDataSourceHolder.getMasterSlaveDataSource() != null) {
            return proceed(methodInvocation);
        }

        // 根据数据源名称获取当前数据源，若当前方法有SpecifyDataSource注解，则方法上注解优先类上注解注解
        SpecifyDataSource specifyDataSource;
        if (elementType == ElementType.METHOD && method.isAnnotationPresent(SpecifyDataSource.class)) {
            specifyDataSource = method.getAnnotation(SpecifyDataSource.class);
        } else if (elementType == ElementType.TYPE && mapperInterface.isAnnotationPresent(SpecifyDataSource.class)) {
            specifyDataSource = mapperInterface.getAnnotation(SpecifyDataSource.class);
        } else {
            return proceed(methodInvocation);
        }

        // 确定使用哪个数据源
        try {
            EasyMsMasterSlaveDataSourceHolder.putMasterSlaveDataSource(easyMsMultiDataSource.getDataSource(specifyDataSource.value()));
            return proceed(methodInvocation);
        } finally {
            EasyMsMasterSlaveDataSourceHolder.clearMasterSlaveDataSource();
        }
    }

    public SpecifyDataSourceInterceptor(EasyMsMultiDataSource easyMsMultiDataSource, ElementType elementType) {
        this.easyMsMultiDataSource = easyMsMultiDataSource;
        this.elementType = elementType;
    }

}